#include "PacketQueue.h"
#include "VDPlayer.h"
#include <assert.h>

PacketQueue::PacketQueue(AVStream* stream)
{
	Init_Mutex(mutex);
	Init_Condition(condition);
	
	av_init_packet(&flushPkt);
	flush_pkt = &flushPkt;
	flush_pkt->data = (uint8_t *)flush_pkt;
	this->stream = stream;

}


PacketQueue::~PacketQueue()
{
	ClearQueue();

	Destroy_Mutex(mutex);
	Destroy_Condition(condition);
}


void PacketQueue::Release()
{
	isExit = true;
	Cond_Signal_All(condition);
}


int PacketQueue::EnqueueEmptyPkt()
{
	AVPacket* pkt = av_packet_alloc();
	pkt->data = NULL;
	pkt->size = 0;
	return Enqueue(pkt);
}

int PacketQueue::EnqueueFlushPkt()
{
	return Enqueue(flush_pkt);
}

int PacketQueue::Enqueue(AVPacket* pkt)
{
	if (isExit)
	{
		if(pkt != flush_pkt)
			AVPacket_Free(&pkt);
		return -1;
	}
	Mutex_Lock(mutex);
	PacketNode* node = new PacketNode();

	if (pkt == flush_pkt)
	{
		serial++;
	}
	node->serial = serial;
	node->pkt = pkt;

	size++;
	byteSize += node->pkt->size + sizeof(*node);
	duration += node->pkt->duration;

	pktlist.push_back(node);
	Cond_Signal_One(condition);
	Mutex_Unlock(mutex);
	return 0;
}

int PacketQueue::Denqueue(AVPacket* &pkt, int *serial)
{
	if (isExit) return -1;
	Mutex_Lock(mutex);
	while (!isExit)
	{
		if (size > 0)
		{
			PacketNode* node = pktlist.front();
			pktlist.pop_front();
			pkt = node->pkt;
			*serial = node->serial;
			size--;
			byteSize -= node->pkt->size + sizeof(*node);
			duration -= node->pkt->duration;
			//printf("[%d]", node->serial);
			delete node;
			node = NULL;
			break;
		}
		else
		{
			Cond_Wait(condition, mutex);
			if (isExit)
			{
				Mutex_Unlock(mutex);
				return -1;
			}
		}
	}
	Mutex_Unlock(mutex);
	return pkt ? 0 : -1;
}

void PacketQueue::ClearQueue()
{
	Mutex_Lock(mutex);
	while (!pktlist.empty())
	{
		PacketNode* node = pktlist.front();
		pktlist.pop_front();
		if (node->pkt != flush_pkt)
			AVPacket_Free(&node->pkt);
		delete node;
	}
	size = 0;
	byteSize = 0;
	duration = 0;

	Mutex_Unlock(mutex);
}

